﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.Net;
using System.IO;
using System.Threading;

namespace ArgusLib.Xml
{
	public enum ReleaseStatus : byte
	{
		Other,
		Alpha,
		Beta,
		RC,
		Stable
	}

	public abstract class UpdateInfo
	{
		public string BuildName { get; private set; }
		public ReleaseStatus ReleaseStatus { get; private set; }
		public Version BuildVersion { get; private set; }
		public string HomepageLink { get; private set; }
		public string DownloadLink { get; private set; }
		public string DirectDownloadLink { get; private set; }
		public int CRC32 { get; private set; }
		public string[] Description { get; private set; }

		protected UpdateInfo() { }

		public UpdateInfo(
			string buildName, ReleaseStatus releaseStatus, Version buildVersion, string homepageLink,
			string downloadLink, string directDownloadLink, int crc32, params string[] description)
		{
			this.BuildName = buildName;
			this.ReleaseStatus = releaseStatus;
			this.BuildVersion = buildVersion;
			this.HomepageLink = homepageLink;
			this.DownloadLink = downloadLink;
			this.DirectDownloadLink = directDownloadLink;
			this.CRC32 = crc32;
			this.Description = description;
		}

		protected abstract string GetDownloadSource();
		protected abstract string GetXmlRootName();

		public void Save(Stream stream)
		{
			using (Serializer seri = Serializer.FromStream(stream, this.GetXmlRootName()))
			{
				seri.Serialize(this);
			}
		}

		public static T Load<T>(Stream stream) where T:UpdateInfo, new()
		{
			T updateInfo = new T();
			using (Deserializer deseri = Deserializer.FromStream(stream))
			{
				if (deseri.RootName != updateInfo.GetXmlRootName())
					return null;
				return deseri.Deserialize() as T;
			}
		}

		public static T Download<T>() where T:UpdateInfo, new()
		{
			T updateInfo = new T();
			try
			{
				WebRequest request = WebRequest.Create(updateInfo.GetDownloadSource());
				WebResponse response = request.GetResponse();
				byte[] buffer;
				using (Stream stream = response.GetResponseStream())
				{
					buffer = new byte[response.ContentLength];
					stream.Read(buffer, 0, buffer.Length);
				}
				if (buffer == null)
					return null;
				//string test = Encoding.UTF8.GetString(buffer);
				using (MemoryStream ms = new MemoryStream(buffer))
				{
					return UpdateInfo.Load<T>(ms);
				}
			}
			catch (WebException)
			{
				return null;
			}
		}

		public static void DownloadAsync<T>(Action<T> callback) where T : UpdateInfo, new()
		{
			ThreadPool.QueueUserWorkItem(new WaitCallback((arg) =>
				{
					T updateInfo = UpdateInfo.Download<T>();
					callback(updateInfo);
				}));
		}
	}
}
